package com.uduemc.biso.node.web.api.controller;

import java.io.File;
import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.uduemc.biso.core.utils.JsonResult;
import com.uduemc.biso.node.web.api.service.VirtualFolderService;
import com.uduemc.biso.node.web.api.service.hostsetup.HSVirtualFolderService;

import cn.hutool.core.io.FileUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@RestController
@RequestMapping("/api/virtual-folder")
@Api(tags = "虚拟目录模块")
public class VirtualFolderController {

	@Autowired
	VirtualFolderService virtualFolderServiceImpl;

	@Autowired
	HSVirtualFolderService hSVirtualFolderServiceImpl;

	/**
	 * 允许上传文件的后缀
	 * 
	 * @return
	 */
	@PostMapping("/upload-allow-suffix")
	@ApiOperation(value = "允许上传文件的后缀", notes = "数据列表的方式返回允许上传文件的后缀")
	public JsonResult uploadAllowSuffix() {
		return JsonResult.ok(hSVirtualFolderServiceImpl.uploadSuffix());
	}

	/**
	 * 允许上传文件的大小
	 * 
	 * @return
	 */
	@PostMapping("/upload-allow-size")
	@ApiOperation(value = "允许上传文件的大小", notes = "返回一个整数，最小单位b，如果要得到M的结果可以通过结果除以(1024*1024)获得")
	public JsonResult allowSize() {
		return JsonResult.ok(hSVirtualFolderServiceImpl.size());
	}

	/**
	 * 允许修改文件内容的后缀
	 * 
	 * @return
	 */
	@PostMapping("/content-allow-suffix")
	@ApiOperation(value = "允许修改内容后缀", notes = "数据列表的方式返回允许修改文件内容的后缀")
	public JsonResult contentAllowSuffix() {
		return JsonResult.ok(hSVirtualFolderServiceImpl.contentSuffix());
	}

	/**
	 * 虚拟目录占用的总空间大小
	 * 
	 * @return
	 */
	@PostMapping("/total-size")
	@ApiOperation(value = "虚拟目录总占用空间", notes = "虚拟目录占用的总空间大小，返回一个整数，最小单位b，如果要得到M的结果可以通过结果除以(1024*1024)获得")
	public JsonResult totalSize() {
		return JsonResult.ok(FileUtil.size(new File(virtualFolderServiceImpl.makeDirectory(null))));
	}

	/**
	 * 上传文件至虚拟目录下，如果目录为空则上传至虚拟根目录下，如果存在格式如下 [目录1]/[目录2]/[目录3]/..../[目录n]
	 * 
	 * @param file
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/upload")
	@ApiOperation(value = "上传文件", notes = "上传的文件有一定的校验规则\n"
			+ "通过 /api/virtual-folder/upload-allow-suffix 获取到允许上传的文件后缀，没有后缀不允许上传\n"
			+ "通过 /api/virtual-folder/upload-allow-size 获取到允许上传的文件大小\n" + "上传的文件名规则：中文、英文、数字、空格、.、-、_，头尾只能中文、英文、数字\n")
	@ApiImplicitParams({ @ApiImplicitParam(name = "file", value = "需要上传的文件", required = true),
			@ApiImplicitParam(name = "directory", value = "上传的文件路径，多级目录用 / 分隔，如果为空则上传至用户虚拟根目录下，参数默认为空") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明上传成功") })
	public JsonResult upload(@RequestPart("file") MultipartFile file,
			@RequestParam(value = "directory", required = false, defaultValue = "") String directory)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.upload(file, directory);
	}

	/**
	 * 获取目录的列表
	 * 
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/ls")
	@ApiOperation(value = "目录下详情", notes = "通过参数返回某一个目录下的文件、目录信息列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "directory", value = "多级目录用 / 分隔，如果参数为空则获取虚拟根目录下的文件、目录信息列表，如果制定特定的目录，则获取该目录下的文件、目录信息列表列表") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 数据列表说明见 /api/virtual-folder/file 接口返回内容说明") })
	public JsonResult ls(@RequestParam(value = "directory", required = false, defaultValue = "") String directory)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.ls(directory);
	}

	/**
	 * 创建目录
	 * 
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/mkdir")
	@ApiOperation(value = "创建目录", notes = "通过参数创建目录，支持多级目录创建")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "directory", required = true, value = "多级目录用 / 分隔，例如：aa-虚拟根目录下创建一个aa的目录， bb/cc/dd-虚拟根目录下创建bb目录，bb目录下创建cc目录，cc目录下创建dd目录，最高可创建嵌套20层级的目录（前端注意：最好只能一级一级的目录创建，不能多级目录创建）") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明创建目录成功") })
	public JsonResult mkdir(@RequestParam(value = "directory") String directory)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.mkdirs(directory);
	}

	/**
	 * 删除目录，必须保证目录为空方可进行删除
	 * 
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/del-directory")
	@ApiOperation(value = "删除目录", notes = "通过参数删除目录，准确定位到要删除目录的层级")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "directory", required = true, value = "目录必须为空方可删除，多级目录用 / 分隔，只删除最后一级的目录，例如：bb/cc/dd-只删除虚拟根目录下cc目录") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明删除目录成功") })
	public JsonResult delDirectory(@RequestParam(value = "directory") String directory)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.delDirectory(directory);
	}

	/**
	 * 删除文件
	 * 
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/del-file")
	@ApiOperation(value = "删除文件", notes = "通过参数删除文件，准确定位到要删除文件的路径，前端要给与提示")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "filepath", required = true, value = "必须有效的文件路径，例如：aa/bb/cc/abc.txt-删除abc.txt文件") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明删除文件成功") })
	public JsonResult delFile(@RequestParam(value = "filepath") String filepath)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.delFile(filepath);
	}

	/**
	 * 清楚目录下的所有文件以及目录，参数如果传入过来的是空字符串，则清除整个虚拟目录下的所有文件以及目录
	 * 
	 * @param directory
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/clean")
	@ApiOperation(value = "清除目录", notes = "通过参数清除目录下的所有文件、目录内容，前端一定要给与高亮提示")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "directory", required = true, value = "必须有效的目录，多级目录用 / 分隔，传入空字符串则清空整个虚拟目录下的所有文件、目录内容，例如：aa/bb-虚拟目录/aa/bb下的所有文件、目录内容") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明清楚目录成功") })
	public JsonResult clean(@RequestParam(value = "directory") String directory)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.loopDelDirectory(directory);
	}

	/**
	 * 获取单个文件的内容以及其他信息
	 * 
	 * @param filepaht
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/file")
	@ApiOperation(value = "获取文件信息", notes = "通过参数准确定位到要获取信息的文件路径")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "filepath", required = true, value = "必须有效的文件路径，例如：aa/bb/cc/abc.txt-获取abc.txt文件信息") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 FolderTree 类型的数据结构\n" + "type 文件或目录的类型\n"
			+ "type.directory 布尔类型，是否是目录\n" + "type.mimeType 文件MIMEType，前端暂时无用\n" + "type.suffix 文件的后缀，目录没有\n"
			+ "name 文件或目录的名称，例如：文件aa/bb/cc/abc.txt-abc.txt，目录aa/bb/cc-cc\n" + "path 文件或目录相对虚拟目录下的路径，多用于其他方法的参数传递\n"
			+ "content 文件内容，只有具体内的文件会返回内容，例如：图片、字体等返回的内容为空\n" + "size 文件或者目录的大小\n" + "href 对应前台默认域名访问的地址\n"
			+ "modified 文件最后一次修改的时间，时间格式为时间戳，Linux不记录文件的创建时间，所以这里不体现文件的创建时间。在不提供文件修改的情况，可以把这个当成文件的创建时间\n"
			+ "child 如果是目录的情况下，对应此目录下的文件信息数据列表，结构于此相同\n") })
	public JsonResult file(@RequestParam(value = "filepath") String filepath)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		return virtualFolderServiceImpl.contentFile(filepath);
	}

	/**
	 * 将内容写入到文件当中
	 * 
	 * @param filepath
	 * @param content
	 * @return
	 */
	@PostMapping("/save-file")
	@ApiOperation(value = "文件写入内容", notes = "通过 filepath 参数准确定位到文件路径，再将 content 参数传递的内容写入到文件中")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "filepath", required = true, value = "必须有效的文件路径，例如：aa/bb/cc/abc.txt-获取abc.txt文件信息"),
			@ApiImplicitParam(name = "content", required = true, value = "写入文件的内容，参数必传，可以为空") })
	@ApiResponses({ @ApiResponse(code = 200, message = "data 为 1 说明写入文件成功") })
	public JsonResult saveFile(@RequestParam(value = "filepath") String filepath,
			@RequestParam(value = "content") String content) {
		return virtualFolderServiceImpl.saveFile(filepath, content);
	}
}
